#include <malloc.h>
#include <stdbool.h>
#include <stdint.h>

typedef struct {
	uint32_t in_index;
	uint32_t out_index;
	uint32_t capacity;
	int32_t buf_a[];
} MyCircularQueue;

static uint32_t _next(uint32_t old_index, uint32_t capacity) {
	uint32_t new_index = old_index + 1;
	if (new_index > capacity) {
		new_index -= (capacity + 1);
	}
	return new_index;
}

static uint32_t _prev(uint32_t old_index, uint32_t capacity) {
	uint32_t new_index = old_index - 1;
	if (new_index > capacity) {
		new_index += (capacity + 1);
	}
	return new_index;
}

MyCircularQueue* myCircularQueueCreate(int capacity) {
	MyCircularQueue* queue_p =
		malloc(sizeof(MyCircularQueue) + sizeof(int[capacity + 1]));
	queue_p->in_index = 0;
	queue_p->out_index = 0;
	queue_p->capacity = capacity;
	return queue_p;
}

bool myCircularQueueEnQueue(MyCircularQueue* queue_p, int value) {
	uint32_t old_in_index = queue_p->in_index;
	uint32_t new_in_index = _next(old_in_index, queue_p->capacity);
	if (new_in_index == queue_p->out_index) {
		return false;
	}
	queue_p->in_index = new_in_index;
	queue_p->buf_a[old_in_index] = value;
	return true;
}

bool myCircularQueueIsEmpty(MyCircularQueue* queue_p) {
	return queue_p->in_index == queue_p->out_index;
}

bool myCircularQueueDeQueue(MyCircularQueue* queue_p) {
	if (myCircularQueueIsEmpty(queue_p)) {
		return false;
	}
	uint32_t new_out_index = _next(queue_p->out_index, queue_p->capacity);
	queue_p->out_index = new_out_index;
	return true;
}

int myCircularQueueFront(MyCircularQueue* queue_p) {
	if (myCircularQueueIsEmpty(queue_p)) {
		return -1;
	}
	return queue_p->buf_a[queue_p->out_index];
}

int myCircularQueueRear(MyCircularQueue* queue_p) {
	if (myCircularQueueIsEmpty(queue_p)) {
		return -1;
	}
	uint32_t prev_in_index = _prev(queue_p->in_index, queue_p->capacity);
	return queue_p->buf_a[prev_in_index];
}

bool myCircularQueueIsFull(MyCircularQueue* queue_p) {
	uint32_t old_in_index = queue_p->in_index;
	uint32_t new_in_index = _next(old_in_index, queue_p->capacity);
	return new_in_index == queue_p->out_index;
}

void myCircularQueueFree(MyCircularQueue* queue_p) {
	free(queue_p);
}
